//    Travel US - For users of travel.usairways.com
//    intended for US Airways employees and their dependents
//    This app will help you track your flights and display
//    Availability, flight status and other non-rev info
//    Copyright (C) 2014  Renats Stozkovs
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

package com.bc004346.travelus.Utility;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;

import com.bc004346.travelus.DataAccess.TravelUsScreenScraper;
import com.bc004346.travelus.Model.Domain.Flight;
import com.bc004346.travelus.Model.Domain.Passenger;
import com.bc004346.travelus.Model.Domain.Reservation;
import com.bc004346.travelus.Model.TravelUsException;
import com.bc004346.travelus.R;
import com.google.analytics.tracking.android.EasyTracker;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;

import static android.provider.Settings.Secure;

/**
 * Created by rstozkov on 1/24/14.
 * Logs and messages
 */
public class Utility {

    //<editor-fold desc="Public Constants">

    public static final String LOGIN_TASK_TAG = "loginTaskTag";
    public static final String SEARCH_TASK_TAG = "searchTaskTag";
    public static final String SELECT_PASSENGER_TAG = "selectPaxTag";
    public static final String GET_PRICE_TAG = "getPriceTag";
    public static final String COMPLETE_BOOKING_TAG = "completeBookingTag";
    public static final String SELECT_FLIGHT_TAG = "selectFlightTag";
    public static final String SELECT_PASSENGERS_TAG = "selectPassengersTag";
    public static final String UPDATE_FLIGHT_AVAILABILITY_TAG = "updateFlightAvailabilityTag";
    public static final String GET_NOTICES_TAG = "getNoticesTag";
    public static final String ORIGIN = "origin";
    public static final String DESTINATION = "destination";
    public static final String DEPARTURE = "departure";
    public static final String RETURN = "return";
    public static final String IS_ONE_WAY = "getRadioButtonOneWay";
    public static final String FLIGHT_SEARCH_PARAMS = "flightSearchParams";
    public static final long SECOND = 1000;
    public static final long MINUTE = 60 * SECOND;
    public static final long HOUR = 60 * MINUTE;
    public static final long DAY = 24 * HOUR;
    public static final DateFormat LONG_DATE = new SimpleDateFormat(
            "EEE, MMM dd, yyyy");
    public static final DateFormat DAY_DATE = new SimpleDateFormat(
            "EEE, MMM dd");
    public static final DateFormat FULL_DATE = new SimpleDateFormat(
            "MM/dd/yyyy HH:mm");
    public static final DateFormat DATE = new SimpleDateFormat(
            "MM/dd/yyyy");
    public static final DateFormat DATE_DASHES = new SimpleDateFormat(
            "yyyy-MM-dd");
    public static final DateFormat SHORT_DATE = new SimpleDateFormat(
            "MM/dd/yy");
    public static final DateFormat MONTH_DAY_DATE = new SimpleDateFormat(
            "MMM dd");
    public static final DateFormat DATE_TIME = new SimpleDateFormat(
            "MMM dd HH:mm:ss");
    public static final DateFormat SHORT_TIME = new SimpleDateFormat(
            "hh:mm aa");
    public static final DateFormat MILITARY_TIME = new SimpleDateFormat(
            "k:mm");
    public static final String USER_SETTINGS = "UserSettings";
    // user settings
    public static final String PNR_REFRESH_ENABLED = "pnr_refresh_enabled";
    public static final String PNR_REFRESH_INTERVAL = "pnr_refresh_interval";
    public static final String DAYS_TO_SEARCH = "days_to_search";
    public static final String AVAILABILITY_REFRESH_ENABLED = "availability_refresh_enabled";
    public static final String AVAILABILITY_REFRESH_INTERVAL = "availability_refresh_interval";
    public static final String AUTO_CHECKIN_ENABLED = "auto_checkin";
    public static final String SEND_ERROR_REPORTS = "boolean_send_error_reports";
    private static final String USERNAME = "username";
    private static final String PASSWORD = "password";
    private static final String NAME = "name";
    private static final String BADGE = "badge";
    private static final String SENIORITY = "seniority";
    private static final String PNR_REFRESH_DATE = "pnrRefreshDate";
    private static final String SHOW_CUSTOM_MESSAGE = "showCustomMessage";
    private static final String LOG_TAG = "TravelUS";
    //</editor-fold>
    //<editor-fold desc="Members">
    public static ArrayList<Flight> flightsSelection;
    public static List<Passenger> paxSelection;
    public static Reservation confirmedReservation;
    public static TravelUsScreenScraper mTravelUS;
    public static TravelUsScreenScraper mTravelUSBackground;
    public static String name;
    public static Date seniority;
    public static String badge;
    public static String username;
    public static String password;
    //public static String daysToSearch;
    //public static String availabilityRefreshInterval;
    //public static String pnrRefreshInterval;
    //public static Boolean pnrRefreshEnabled;
    //public static Boolean availabilityRefreshEnabled;
    //public static Boolean autoCheckinEnabled;
    public static Boolean showCustomMessage;
    public static Date pnrRefreshDate;
    //    public static InputFilter dateInputFilter = new InputFilter() {
//        public CharSequence filter(CharSequence source, int start, int end,
//                                   Spanned dest, int dstart, int dend) {
//            Integer value;
//            try {
//                value = Integer.parseInt(String.valueOf(source));
//            } catch (NumberFormatException e) {
//                return null;
//            }
//            // month
//            if (dstart == 0 && (value < 0 || value > 1)) return "";
//            if (dstart == 1) return source + "/";
//
//            //day
//            if (dstart == 3 && (value < 0 || value > 3)) return "";
//            if (dstart == 4) return source + "/";
//
//            // year
//            if (dstart == 6 && value < 1) return "";
//            if (dstart == 7 && (value < 0 || value > 9)) return "";
//            if (dstart == 8) return "";
//            return null;
//        }
//    };
    private static String deviceId;
    private static ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(10);
    private static Utility mInstance = new Utility();
    private static Activity mActivity;

    //</editor-fold>

    //<editor-fold desc="Constructors">

    private Utility() {
    }

    //</editor-fold>

    //<editor-fold desc="Properties">

    public static Boolean pnrRefreshEnabled() {
        return PreferenceManager
                .getDefaultSharedPreferences(mActivity)
                .getBoolean(PNR_REFRESH_ENABLED, true);
    }

    public static String pnrRefreshInterval() {
        return PreferenceManager
                .getDefaultSharedPreferences(mActivity)
                .getString(PNR_REFRESH_INTERVAL, "3");
    }

    public static Boolean availabilityRefreshEnabled() {
        return PreferenceManager
                .getDefaultSharedPreferences(mActivity)
                .getBoolean(AVAILABILITY_REFRESH_ENABLED, true);
    }

    public static String availabilityRefreshInterval() {
        return PreferenceManager
                .getDefaultSharedPreferences(mActivity)
                .getString(AVAILABILITY_REFRESH_INTERVAL, "3");
    }

    public static String daysToSearch() {
        return PreferenceManager
                .getDefaultSharedPreferences(mActivity)
                .getString(DAYS_TO_SEARCH, "30");
    }

    public static Boolean sendErrorReportsEnabled() {
        return PreferenceManager
                .getDefaultSharedPreferences(mActivity)
                .getBoolean(SEND_ERROR_REPORTS, true);
    }

    public static Boolean autoCheckinEnabled() {
        return PreferenceManager
                .getDefaultSharedPreferences(mActivity)
                .getBoolean(AUTO_CHECKIN_ENABLED, true);
    }

    public static void setSendErrorReportsEnabled(Boolean b) {
        SharedPreferences settings = PreferenceManager
                .getDefaultSharedPreferences(mActivity);
        SharedPreferences.Editor editor = settings.edit();
        editor.putBoolean(SEND_ERROR_REPORTS, b);
        editor.apply();
    }

    //</editor-fold>

    //<editor-fold desc="Methods">

    public static void onStart(Activity activity) throws ParseException {

        mActivity = activity;
        SharedPreferences settings = activity.getSharedPreferences(USER_SETTINGS, 0);
        username = settings.getString(USERNAME, "");
        password = settings.getString(PASSWORD, "");
        name = settings.getString(NAME, "");
        badge = settings.getString(BADGE, "0");
        seniority = DATE.parse(settings.getString(SENIORITY, "01/01/2000"));
        pnrRefreshDate = FULL_DATE.parse(settings.getString(PNR_REFRESH_DATE, "01/01/2000 00:00"));
        showCustomMessage = settings.getBoolean(SHOW_CUSTOM_MESSAGE, true);
    }

    //</editor-fold>

    //<editor-fold desc="Public Methods">

    public static void onStop(Activity activity) {

        SharedPreferences settings = activity.getSharedPreferences(USER_SETTINGS, 0);
        SharedPreferences.Editor editor = settings.edit();
        editor.putString(USERNAME, username);
        editor.putString(PASSWORD, password);
        editor.putString(NAME, name);
        editor.putString(BADGE, badge);
        editor.putString(SENIORITY, DATE.format(seniority));
        editor.putString(PNR_REFRESH_DATE, FULL_DATE.format(pnrRefreshDate));
        editor.putBoolean(SHOW_CUSTOM_MESSAGE, showCustomMessage);
        editor.apply();
    }

    public static void onActivityStart(Activity activity) {

        if (deviceId == null || deviceId.length() == 0)
            deviceId = Secure.getString(activity.getContentResolver(), Secure.ANDROID_ID);
        if (!deviceId.equals("32218b20b54fd3e4"))
            EasyTracker.getInstance(activity).activityStart(activity);
    }

    public static void onActivityStop(Activity activity) {

        if (deviceId == null || deviceId.length() == 0)
            deviceId = Secure.getString(activity.getContentResolver(), Secure.ANDROID_ID);
        if (!deviceId.equals("32218b20b54fd3e4"))
            EasyTracker.getInstance(activity).activityStop(activity);
    }

    public static Utility getInstance() {
        return mInstance;
    }

    public static void log(String... params) {

        StringBuilder sb = new StringBuilder();
        StackTraceElement signature = Thread.currentThread().getStackTrace()[3];
        sb.append(DATE_TIME.format(new Date()))
                .append(" -> ")
                .append(signature.getClassName())
                .append(" -> ")
                .append(signature.getMethodName())
                .append(" -> ");
        for (String st : params) sb.append(st);
        Log.d(LOG_TAG, sb.toString());
        if (queue.remainingCapacity() == 0) queue.poll();
        queue.offer(sb.toString());
    }

    public static void log(Exception e, Activity a) {
        log("\n" + "getMessage: " + e.getMessage() + "\n" + "toString: " + e.toString() + "\n"
                + "getStackTrace" + Arrays.toString(e.getStackTrace()));
        if (a != null) sendReport(a);
    }

    private static void sendReport(Activity theActivity) {

        if (sendErrorReportsEnabled() != null && sendErrorReportsEnabled()) {

            final Activity activity = theActivity;

            new AlertDialog.Builder(activity)
                    .setTitle(activity.getString(R.string.app_name))
                    .setIcon(android.R.drawable.ic_dialog_info)
                    .setMessage(activity.getString(R.string.utilityMessage_ErrorReport))
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            prepareAndSendEmail(activity);
                        }
                    })
                    .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            setSendErrorReportsEnabled(false);
                        }
                    })
                    .show();
        }
    }

    //</editor-fold>

    //<editor-fold desc="Private Methods">

    public static void prepareAndSendEmail(Activity activity) {

        StringBuilder sb = new StringBuilder();
        final Intent intent = new Intent(Intent.ACTION_SEND);

        try {
            sb.append("System Info\n");
            sb.append(String.format("Device = %s\n", Build.DEVICE));
            sb.append(String.format("SDK = %d\n", Build.VERSION.SDK_INT));
            sb.append(String.format("Version = %s\n", Build.VERSION.RELEASE));
            sb.append(String.format("Model = %s\n", Build.MODEL));
            sb.append(String.format("Product = %s\n", Build.PRODUCT));
            sb.append(String.format("Display = %s\n", Build.DISPLAY));
            String packageName = activity.getPackageName();
            PackageManager pm = activity.getPackageManager();
            if (pm != null) {
                sb.append(String.format("Version Name = %s\n", pm.getPackageInfo(packageName, 0).versionName));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        sb.append("\n\nRecent logs\n");
        for (String message : queue) {
            sb.append(message);
            sb.append("\n\n");
        }

        intent.setType("message/rfc822");
        intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"bc004346@gmail.com"});
        intent.putExtra(Intent.EXTRA_SUBJECT, "Travel US Exception report");
        intent.putExtra(Intent.EXTRA_TEXT, sb.toString());
        try {
            activity.startActivity(Intent.createChooser(intent, "Send mail..."));
        } catch (ActivityNotFoundException ex) {
            log(ex.getMessage());
        }
    }

    public TravelUsScreenScraper getTravelUS() {
        if (mTravelUS == null)
            mTravelUS = new TravelUsScreenScraper(name, username, seniority);
        return mTravelUS;
    }

    public TravelUsScreenScraper getBackgroundTravelUS() throws IOException, TravelUsException {
        if (mTravelUSBackground == null) {
            mTravelUSBackground = new TravelUsScreenScraper(name, username, seniority);
            mTravelUSBackground.doLogin(username, password);
        }

        return mTravelUSBackground;
    }

    //</editor-fold>
}
